﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MySql.Data;
using MySql.Data.Entity;
using MySql.Data.MySqlClient;

namespace PreProcessingLanguage
{
    class NgramSql
    {
        //Sql property
        private MySqlConnection connection;
        private string server;
        private int port;
        private string database;
        private string uid;
        private string password;

        //NgramSql property
        private bool allowDelCount = true;
        private int countDel = 5;

        //Constructor
        public NgramSql()
        {
            Initialize();
        }

        //Initialize values
        private void Initialize()
        {
            server = "localhost";
            port = 3306;
            database = "word";
            uid = "root";
            password = "";
            string connectionString = "SERVER=" + server + ";" + "Port =" + port + ";" + "DATABASE=" +
                database + ";" + "UID=" + uid + ";" + "PASSWORD=" + password + ";CHARSET=utf8;";
            //server = "db4free.net";
            //port = 3306;
            //database = "ichat";
            //uid = "siduko";
            //password = "bomman";
            //string connectionString = "SERVER=" + server + ";" + "Port =" + port + ";" + "DATABASE=" +
            //    database + ";" + "UID=" + uid + ";" + "PASSWORD=" + password + ";CHARSET=utf8;";
            Console.WriteLine("Initializing database...");
            connection = new MySqlConnection(connectionString);
            Console.WriteLine("Connecting database...");
            connection.Open();
            Console.WriteLine("Connected.");
        }

        //open connection to database
        private bool OpenConnection()
        {
            try
            {
                connection.Open();
                return true;
            }
            catch (MySqlException ex)
            {
                //When handling errors, you can your application's response based 
                //on the error number.
                //The two most common error numbers when connecting are as follows:
                //0: Cannot connect to server.
                //1045: Invalid user name and/or password.
                switch (ex.Number)
                {
                    case 0:
                        Console.WriteLine("Cannot connect to server.  Contact administrator");
                        break;

                    case 1045:
                        Console.WriteLine("Invalid username/password, please try again");
                        break;
                }
                return false;
            }
        }

        //Close connection
        private bool CloseConnection()
        {
            try
            {
                connection.Close();
                return true;
            }
            catch (MySqlException ex)
            {
                Console.WriteLine(ex.Message);
                return false;
            }
        }

        private Dictionary<string, double> P1ContainsKey(string key)
        {
            Dictionary<string, double> kq = new Dictionary<string, double>();
            string query = "SELECT `value` FROM `word1` WHERE `word`='" + key + "'";
            //Create Command
            MySqlCommand cmd = new MySqlCommand(query, connection);
            //Create a data reader and Execute the command
            MySqlDataReader dataReader = cmd.ExecuteReader();
            if (dataReader.Read())
            {
                string[] ss = dataReader["value"].ToString().Split(';');
                string[] sss;
                foreach (string s in ss)
                {
                    sss = s.Split('-');
                    kq.Add(sss[0], double.Parse(sss[1]));
                }
            }
            dataReader.Close();
            return kq;
        }
        private Dictionary<string, double> P2ContainsKey(string key)
        {
            Dictionary<string, double> kq = new Dictionary<string, double>();
            string query = "SELECT `value` FROM `word2` WHERE `word`='" + key + "'";
            //Create Command
            MySqlCommand cmd = new MySqlCommand(query, connection);
            //Create a data reader and Execute the command
            MySqlDataReader dataReader = cmd.ExecuteReader();
            if (dataReader.Read())
            {
                string[] ss = dataReader["value"].ToString().Split(';');
                string[] sss;
                foreach (string s in ss)
                {
                    sss = s.Split('-');
                    kq.Add(sss[0], double.Parse(sss[1]));
                }
            }
            dataReader.Close();
            return kq;
        }
        private Dictionary<string, double> P3ContainsKey(string key)
        {
            Dictionary<string, double> kq = new Dictionary<string, double>();
            string query = "SELECT `value` FROM `word3` WHERE `word`='" + key + "'";
            //Create Command
            MySqlCommand cmd = new MySqlCommand(query, connection);
            //Create a data reader and Execute the command
            MySqlDataReader dataReader = cmd.ExecuteReader();
            dataReader.Read();
            if (dataReader.Read())
            {
                string[] ss = dataReader["value"].ToString().Split(';');
                string[] sss;
                foreach (string s in ss)
                {
                    sss = s.Split('-');
                    kq.Add(sss[0], double.Parse(sss[1]));
                }
            }
            dataReader.Close();
            return kq;
        }

        public string getKq(Dictionary<string, double> kq)
        {
            try
            {
                double max = kq.Max(kvp => kvp.Value);
                return kq.Where(kvp => kvp.Value == max).Select(kvp => kvp.Key).First();
            }
            catch (Exception)
            {
                return null;
            }
        }

        public Dictionary<string, double> getKqForCount(Dictionary<string, double> dict, int count)
        {
            var items = from pair in dict
                        orderby pair.Value descending
                        select pair;
            Dictionary<string, double> kq = new Dictionary<string, double>();
            foreach (KeyValuePair<string, double> pair in items)
            {
                if (count == 0)
                    return kq;
                count--;
                kq.Add(pair.Key, pair.Value);
            }
            return kq;
        }

        public Dictionary<string, double> process(string input)
        {
            try
            {
                Dictionary<string, double> kq = new Dictionary<string, double>();
                string[] wordsS = input.Split(' ');
                string[] wordsUS = PreProcessing.ConvertToUnSign(input).Split(' ');            //chia thành mảng từ không dấu
                Dictionary<string, double> words;               //danh sách từ có dấu từ 1 từ không dấu
                Dictionary<string, double> listWords;            //danh sách các câu có thể tạo thành từ từ ko dấu
                Dictionary<string, double> temp;                //danh sách tạm
                List<string> temp_word = new List<string>();
                bool isFirst = true;
                words = P1ContainsKey(wordsUS[0]);
                if (words.Count == 0)
                {
                    words = new Dictionary<string, double>();
                    words.Add(wordsUS[0], 1.0);
                }
                kq = words;
                temp_word.Add(wordsUS[0]);

                if (wordsUS.Length >= 2)
                {
                    words = P1ContainsKey(wordsUS[1]);
                    if (words.Count == 0)
                    {
                        words = new Dictionary<string, double>();
                        words.Add(wordsUS[1], 1.0);
                    }
                    temp_word.Add(wordsUS[1]);
                    listWords = new Dictionary<string, double>();
                    foreach (KeyValuePair<string, double> pair in kq)
                    {
                        foreach (KeyValuePair<string, double> w in words)
                        {

                            listWords.Add(pair.Key + " " + w.Key, pair.Value);
                        }
                    }
                    temp = new Dictionary<string, double>();

                    Dictionary<string, double> tempP2 = P2ContainsKey(temp_word[0] + " " + temp_word[1]);

                    foreach (KeyValuePair<string, double> s in listWords)
                    {
                        if (tempP2.Count != 0)
                        {
                            if (tempP2.ContainsKey(s.Key))
                            {
                                temp.Add(s.Key, s.Value * tempP2[s.Key] * 1.0);
                            }
                            else
                            {
                                temp.Add(s.Key, s.Value / 100);
                            }
                        }
                        else
                        {
                            temp.Add(s.Key, s.Value / 100);
                        }
                    }
                    if (allowDelCount)
                        kq = getKqForCount(temp, countDel);
                    else
                        kq = temp;

                    for (int i = 2; i < wordsUS.Length; i++)
                    {
                        words = P1ContainsKey(wordsUS[i]);
                        if (words.Count == 0)
                        {
                            words = new Dictionary<string, double>();
                            words.Add(wordsUS[i], 1.0);
                        }
                        temp_word.Add(wordsUS[i]);
                        if (isFirst == false)
                        {
                            temp_word.RemoveAt(0);
                        }
                        isFirst = false;
                        listWords = new Dictionary<string, double>();
                        foreach (KeyValuePair<string, double> pair in kq)
                        {
                            foreach (KeyValuePair<string, double> w in words)
                            {
                                listWords.Add(pair.Key + " " + w.Key, pair.Value * 1.0);
                            }
                        }
                        temp = new Dictionary<string, double>();
                        Dictionary<string, double> tempP3 = P3ContainsKey(temp_word[0] + " " + temp_word[1] + " " + temp_word[2]);
                        foreach (KeyValuePair<string, double> s in listWords)
                        {
                            if (tempP3.Count != 0)
                            {
                                string[] str = s.Key.Split(' ');
                                if (tempP3.ContainsKey(str[str.Length - 3] + " " + str[str.Length - 2] + " " + str[str.Length - 1]))
                                {
                                    temp.Add(s.Key, s.Value * tempP3[str[str.Length - 3] + " " + str[str.Length - 2] + " " + str[str.Length - 1]] * 1.0);
                                }
                                else
                                {
                                    temp.Add(s.Key, s.Value / 100);
                                }
                            }
                            else
                            {
                                temp.Add(s.Key, s.Value / 100);
                            }
                        }
                        if (allowDelCount)
                            kq = getKqForCount(temp, countDel);
                        else
                            kq = temp;
                    }
                }
                return kq;
            }
            catch (Exception e)
            {
                Console.WriteLine("Lỗi:" + e.StackTrace);
            }
            return null;
        }
    }
}
